<template>
  <div style="width: 900px;height: 100vh;">
    <uploader
      ref="uploaderRef"
      :options="options"
      :autoStart="false"
      :file-status-text="fileStatusText"
      class="uploader-ui"
      @file-added="onFileAdded"
      @file-success="onFileSuccess"
      @file-progress="onFileProgress"
      @file-error="onFileError"
    >
      <uploader-unsupport></uploader-unsupport>
      <uploader-drop>
        <p>拖拽文件到此处或</p>
        <uploader-btn id="global-uploader-btn" ref="uploadBtn" :attrs="attrs"
          >选择文件<i class="el-icon-upload el-icon--right"></i
        ></uploader-btn>
      </uploader-drop>
      <uploader-list></uploader-list>
    </uploader>
  </div>
</template>

<script setup>
import { reactive, ref, onMounted } from "vue";
import SparkMD5 from "spark-md5";
import { mergeFile } from "./apis";

const options = reactive({
  //目标上传 URL，默认POST, import.meta.env.VITE_API_URL = api
  // target ==》http://localhost:8000/api/uploader/chunk
  target: "http://localhost:8000/api/uploader/file-slice",
  query: {},
  // headers: {
  //   // 需要携带token信息，当然看各项目情况具体定义
  //   Authorization: "Bearer " + localStorage.getItem("access_token"),
  // },
  //分块大小(单位：字节)
  chunkSize: 1024 * 1024 * 5,
  //上传文件时文件内容的参数名，对应chunk里的Multipart对象名，默认对象名为file
  fileParameterName: "file",
  //失败后最多自动重试上传次数
  maxChunkRetries: 3,
  //是否开启服务器分片校验，对应GET类型同名的target URL
  testChunks: true,
  // 剩余时间
  parseTimeRemaining: function (timeRemaining, parsedTimeRemaining) {
    return parsedTimeRemaining
      .replace(/\syears?/, "年")
      .replace(/\days?/, "天")
      .replace(/\shours?/, "小时")
      .replace(/\sminutes?/, "分钟")
      .replace(/\sseconds?/, "秒");
  },
  // 服务器分片校验函数
  checkChunkUploadedByResponse: function (chunk, response_msg) {
    let objMessage = JSON.parse(response_msg);
    console.log(response_msg, "response_msg");
    if (objMessage.data.isExist) {
      return true;
    }
    return (objMessage.data.uploaded || []).indexOf(chunk.offset + 1) >= 0;
  },
});
const attrs =  reactive({
        // 设置上传文件类型
	   accept: ['.rar','.zip']
	 })
const fileStatusText = reactive({
  success: "上传成功",
  error: "上传失败",
  uploading: "上传中",
  paused: "暂停",
  waiting: "等待上传",
});
onMounted(() => {
  console.log(uploaderRef.value, "uploaderRef.value");
});
function onFileAdded(file) {
  computeMD5(file);
}

async function onFileSuccess(rootFile, file, response, chunk) {
  //refProjectId为预留字段，可关联附件所属目标，例如所属档案，所属工程等
  //   判断是否秒传成功，成功取消合并
  console.log("秒传成功", response);
  let objMessage = JSON.parse(response);
  if (objMessage.data.isExist != null && objMessage.data.isExist == true) {
    console.log("秒传成功", response);
    return;
  }
  const res = await mergeFile({
    filename: file.name, //文件名称
    identifier: file.uniqueIdentifier, //文件唯一标识
    totalChunks: chunk.offset + 1, //文件总分片数
  });
  if (res.code === 200) {
    console.log("上传成功", res);
  } else {
    console.log("上传失败", res);
  }
}
function onFileError(rootFile, file, response, chunk) {
  console.log("上传完成后异常信息：" + response);
}

/**
 * 计算md5，实现断点续传及秒传
 * @param file
 */
function computeMD5(file) {
  file.pause();

  //单个文件的大小限制1G
  let fileSizeLimit = 1 * 1024 * 1024 * 1024;
  console.log("文件大小：" + file.size);
  console.log("限制大小：" + fileSizeLimit);
  if (file.size > fileSizeLimit) {
    file.cancel();
  }

  let fileReader = new FileReader();
  let time = new Date().getTime();
  let blobSlice =
    File.prototype.slice ||
    File.prototype.mozSlice ||
    File.prototype.webkitSlice;
  let currentChunk = 0;
  const chunkSize = 10 * 1024 * 1000;
  let chunks = Math.ceil(file.size / chunkSize);
  let spark = new SparkMD5.ArrayBuffer();
  //如果文件过大计算非常慢，因此采用只计算第1块文件的md5的方式
  let chunkNumberMD5 = 1;

  loadNext();

  fileReader.onload = (e) => {
    spark.append(e.target.result);

    if (currentChunk < chunkNumberMD5) {
      loadNext();
    } else {
      let md5 = spark.end();
      file.uniqueIdentifier = md5;
      // 计算完毕开始上传
      file.resume();
      console.log(
        `MD5计算完毕：${file.name} \nMD5：${md5} \n分片：${chunks} 大小:${
          file.size
        } 用时：${new Date().getTime() - time} ms`
      );
    }
  };

  fileReader.onerror = function () {
    file.cancel();
  };

  function loadNext() {
    let start = currentChunk * chunkSize;
    let end = start + chunkSize >= file.size ? file.size : start + chunkSize;

    fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
    currentChunk++;
    console.log("计算第" + currentChunk + "块");
  }
}
const uploaderRef = ref();
function close() {
  uploaderRef.value.cancel();
}
function error(msg) {
  console.log(msg, "msg");
}
</script>

<style scoped>
.uploader-ui {
  padding: 15px;
  margin: 40px auto 0;
  font-size: 12px;
  font-family: Microsoft YaHei;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
  width: 100%;
}
.uploader-ui .uploader-btn {
  margin-right: 4px;
  font-size: 12px;
  border-radius: 3px;
  color: #fff;
  background-color: #58bfc1;
  border-color: #58bfc1;
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
}
.uploader-ui .uploader-list {
  max-height: 440px;
  overflow: auto;
  overflow-x: hidden;
  overflow-y: auto;
}
</style>